/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.properties; import java.awt.Image; import java.awt.Toolkit; import java.awt.datatransfer.*; import java.beans.*; import java.util.*; import java.io.*; import java.lang.reflect.Array; import java.text.MessageFormat; import java.util.ResourceBundle; import javax.swing.table.*; import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.datatransfer.*; import org.openide.actions.InstantiateAction; import org.openide.util.HelpCtx; import org.openide.util.RequestProcessor; import org.openide.util.NbBundle; import org.openide.util.NbBundle; import org.openide.util.WeakListener; import org.openide.util.actions.SystemAction; import org.openide.nodes.*; import org.openide.loaders.*; import org.openide.*; /** General abstract structure for properties files, in its use similar to source hierarchy. * Interoperates with Document, PropertiesTableModel, Nodes and other display-specific models * Implementations of the model interfaces generally reference this structure. * <br>This structure provides support for sorting entries and fast mapping of integers to entries. * * @author Petr Jiricka */ public class BundleStructure extends PropertyChangeSupport { // PENDING // do lazy initialization of entries, don't parse all at the beginning /** generated Serialized Version UID */ // static final long serialVersionUID = -7882925922830244768L; /** Main dataobject */ PropertiesDataObject obj; /** Array of PropertiesFileEntry */ private Object entries[]; /** List of keys sorted by the alphabet */ private SortedArrayList keyList; protected PropertyBundleSupport support = new PropertyBundleSupport(this); /** Listens to changes on the underlying dataobject */ private PropertyChangeListener pcl; static final long serialVersionUID =-7537975919604619884L; /** Create a data node for a given data object. * The provided children object will be used to hold all child nodes. * @param obj object to work with * @param ch children container for the node */ public BundleStructure (PropertiesDataObject obj) { super (obj); this.obj = obj; updateEntries(); // listener for the DataObject pcl = new PropertyChangeListener () { public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(PropertiesDataObject.PROP_FILES)) { updateEntries(); // PENDING firePropertyChange (evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()); } } }; obj.addPropertyChangeListener(new WeakListener.PropertyChange(pcl)); //PENDING move the column corresponding to curNode to the beginning } /** Retrieves n-th entry from the list, indexed from 0 */ public PropertiesFileEntry getNthEntry(int i) { if (entries != null) return (PropertiesFileEntry)entries[i]; else throw new InternalError(getClass().getName() +" - Entries not initialized"); } /** Retrieves the index of a file entry (primary or secondary) by the name of its file * @return index for entry with the given filename or -1 if not found */ public int getEntryIndexByFileName(String fileName) { if (entries != null) { for (int i = 0; i < getEntryCount(); i++) { if (((PropertiesFileEntry)entries[i]).getFile().getName().equals(fileName)) return i; } return -1; } else throw new InternalError(getClass().getName() +" - Entries not initialized"); } /** Retrieves a file entry (primary or secondary) by the name of its file * @return entry with the given filename or null if not found */ public PropertiesFileEntry getEntryByFileName(String fileName) { int index = getEntryIndexByFileName(fileName); return ((index == -1) ? null : (PropertiesFileEntry)entries[index]); } /** Retrieves number of all entries */ public int getEntryCount() { if (entries != null) return entries.length; else throw new InternalError(getClass().getName() +" - Entries not initialized"); } public String[] getKeys() { if (keyList == null) throw new InternalError(getClass().getName() +" - KeyList not initialized"); Object keyArray[] = keyList.toArray(); String stringArray[] = new String[keyArray.length]; System.arraycopy(keyArray, 0, stringArray, 0, keyArray.length); return stringArray; } /** Retrieves n-th key from the list, indexed from 0 */ public String getNthKey(int keyIndex) { if (keyList == null) throw new InternalError(getClass().getName() +" - KeyList not initialized"); if ((keyIndex >= keyList.size()) || (keyIndex < 0)) return null; return (String)keyList.get(keyIndex); } /** Retrieves index for a key from the list, by name */ public int getKeyIndexByName(String keyName) { return keyList.setContains(keyName); } /** Retrieves keyIndex-th key in the entryIndex-th entry from the list, indexed from 0 * @return item for keyIndex-th key in the entryIndex-th entry * or null if the entry does not contain the key */ public Element.ItemElem getItem(int entryIndex, int keyIndex) { PropertiesFileEntry pfe = getNthEntry(entryIndex); String key = getNthKey(keyIndex); PropertiesStructure ps = pfe.getHandler().getStructure(); if (ps != null) return ps.getItem(key); else return null; } /** Retrieves number of all keys */ public int getKeyCount() { if (keyList != null) return keyList.size(); else throw new InternalError(getClass().getName() +" - KeyList not initialized"); } /** Updates internal entries from the underlying dataobject */ protected synchronized void updateEntries() { TreeMap tm = new TreeMap(PropertiesDataObject.getSecondaryFilesComparator()); PropertiesFileEntry pfe; for (Iterator it = obj.secondaryEntries().iterator(); it.hasNext(); ) { pfe = (PropertiesFileEntry)it.next(); tm.put(pfe.getFile().getName(), pfe); } // move the entries entries = new Object[tm.size() + 1]; entries[0] = obj.getPrimaryEntry(); int index = 0; for (Iterator it = tm.keySet().iterator(); it.hasNext(); ) entries[++index] = tm.get(it.next()); buildKeySet(); } /** Constructs a set of keys from the entries (from scratch) */ protected synchronized void buildKeySet() { keyList = new SortedArrayList(new KeyComparator()); // for all entries add all keys for (int index = 0; index < getEntryCount(); index++) { PropertiesFileEntry entry = getNthEntry(index); PropertiesStructure ps = entry.getHandler().getStructure(); if (ps != null) { for (Iterator it = ps.nonEmptyItems(); it.hasNext(); ) keyList.setAdd(((Element.ItemElem)it.next()).getKey()); } else; //System.out.println("Warning : Properties structure not created / BundleStructure.buildKeySet()"); } } // event methods /** Add a listener to the list that's notified each time a change * to the property bundle occurs. * @param l the PropertyBundleListener */ public void addPropertyBundleListener(PropertyBundleListener l) { support.addPropertyBundleListener(l); } /** Remove a listener from the list that's notified each time a * change to the property bundle occurs. * @param l the PropertyBundleListener */ public void removePropertyBundleListener(PropertyBundleListener l) { support.removePropertyBundleListener(l); } // notification methods from lower layers of the structure /** One item in a properties file has changed. * Fires a change event for this item. */ void itemChanged(Element.ItemElem item) { support.fireItemChanged(item.getParent()/*PropertiesStructure*/ .getParent()/*StructHandler*/ .getEntry()/*PropertiesFileEntry*/ .getFile().getName(), item.getKey()); } /** One file in the bundle has changed - no further information. * Fires changes for a bundle or a file according to the changes in the keys. */ void oneFileChanged(StructHandler handler) { // PENDING - events should be finer // find out whether global key table has changed and fire a change according to that SortedArrayList oldKeyList = keyList; buildKeySet(); if (keyList.equals(oldKeyList)) { support.fireBundleDataChanged(); } else { support.fireFileChanged(handler.getEntry().getFile().getName()); } } /** One file in the bundle has changed, carries information about what particular items have changed. * Fires changes for a bundle or a file according to the changes in the keys. */ void oneFileChanged(StructHandler handler, ArrayMapList itemsChanged, ArrayMapList itemsAdded, ArrayMapList itemsDeleted) { // PENDING - events should be finer // find out whether global key table has changed // should use a faster algorithm of building the keyset buildKeySet(); support.fireBundleDataChanged(); } } /* * <<Log>> */